import random
import uuid
from uuid import uuid4
import pandas as pd
import os
from dataclasses import dataclass, field
from typing import List, Set, Dict, Optional, Union, Tuple, Any
import logging
from datetime import datetime, date, timedelta
from .models import (
    db,
    Elderdemand,
    Attendantskills,
    ScheduleResult,
    TimeSlot,
    DicNursingAction,
    CaregiverSchedule,
)
from config_params import params
from contextlib import contextmanager
import cupy as cp
import time
import numpy as np
from .redis_utils import set_update_flag, set_update_time

# 设置日志记录
logging.basicConfig(
    level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)


# 装饰器函数,用于诊断GPU利用率
def diagnose_gpu_utilization(func):
    def wrapper(*args, **kwargs):
        try:
            start = time.time()

            # 尝试获取初始内存使用情况
            try:
                start_mem = cp.cuda.runtime.memGetInfo()[1] - cp.cuda.runtime.memGetInfo()[0]
            except Exception as e:
                logging.warning(f"获取初始GPU内存信息失败: {str(e)}")
                start_mem = 0

            result = func(*args, **kwargs)

            end = time.time()

            # 尝试获取结束时的内存使用情况
            try:
                end_mem = cp.cuda.runtime.memGetInfo()[1] - cp.cuda.runtime.memGetInfo()[0]
                mem_change = (end_mem - start_mem) / 1024 ** 2
            except Exception as e:
                logging.warning(f"获取结束GPU内存信息失败: {str(e)}")
                end_mem = 0
                mem_change = 0

            # 使用logging代替print，避免控制台编码问题
            logging.info(f"运行 {func.__name__} 使用 {end - start:.2f} 秒")
            logging.info(f"内存使用变化: {mem_change:.2f} MB")

            return result
        except Exception as e:
            logging.error(f"在执行{func.__name__}时发生错误: {str(e)}", exc_info=True)
            raise

    return wrapper


# 定义活动数据类
@dataclass
class Activity:
    name: str
    duration: int
    required_skill: Optional[str] = None
    depends_on: List[str] = field(default_factory=list)


# 定义客户(老人)数据类
@dataclass(frozen=True)
class Client:
    elder: str
    actions: tuple

    def __hash__(self):
        return hash((self.elder, self.actions))

    def __eq__(self, other):
        if not isinstance(other, type(self)):
            return NotImplemented
        return self.elder == other.elder and self.actions == other.actions


# 定义护理人员数据类
@dataclass(frozen=True)
class CaregiverData:
    id: str
    attendant_name: str
    skills: frozenset

    def __hash__(self):
        return hash((self.id, self.attendant_name, self.skills))

    def __eq__(self, other):
        if not isinstance(other, CaregiverData):
            return NotImplemented
        return (self.id, self.attendant_name, self.skills) == (
            other.id,
            other.attendant_name,
            other.skills,
        )


# 定义时间表数据类
@dataclass
class Schedule:
    start_time: float

    def __str__(self):
        start_hour = int(self.start_time)
        start_minute = int((self.start_time % 1) * 60)
        end_time = self.start_time + 0.5
        end_hour = int(end_time)
        end_minute = int((end_time % 1) * 60)
        return f"{start_hour:02d}:{start_minute:02d}-{end_hour:02d}:{end_minute:02d}"


# 定义计划基因数据类
@dataclass
class PlanGenes:
    schedule: Schedule
    caregiver: CaregiverData
    client: Client
    activity: Activity

    def __str__(self):
        return (
            f"TimeSlot: {self.schedule}\n"
            f"  Caregiver: {self.caregiver.attendant_name} (Skills: {self.caregiver.skills})\n"
            f"  Client: {self.client.elder} (Actions: {self.client.actions})\n"
            f"  Activity: {self.activity.name} (Duration: {self.activity.duration} mins, Required Skill: {self.activity.required_skill})\n"
        )


# 定义订单数据类
@dataclass
class Order:
    order: List[PlanGenes]
    fitness: int = 0
    id: str = field(default_factory=lambda: str(uuid.uuid4()))


# 主要的计划类
class Plan:
    def __init__(self, params):
        self.client_num = params["client_num"]
        self.caregiver_num = params["caregiver_num"]
        self.population_size = params["population_size"]
        self.crossover_rate = params["crossover_rate"]
        self.mutation_rate = params["mutation_rate"]
        self.phenotype_limit = params["phenotype_limit"]
        self.tournament_size = int(self.population_size * 0.5)
        self.elimination_size = params["elimination_size"]
        self.meal_activities = frozenset([8, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73])
        self.nursing_actions = self.load_nursing_actions()
        self.clients = []
        self.caregivers = []
        self.orders = []
        self.emergency_slots = self.reserve_emergency_slots()
        self.sleep_times = frozenset(
            [
                0,
                0.5,
                1,
                1.5,
                2,
                2.5,
                3,
                3.5,
                4,
                4.5,
                5,
                5.5,
                6,
                6.5,
                12,
                12.5,
                13,
                13.5,
                14,
            ]
        )
        self.meal_times = {8: "Breakfast", 11.5: "Lunch", 18: "Dinner"}
        self.elder_meal_activities = {}
        self.default_caregiver = self.get_default_caregiver()
        self.lack_caregiver = self.get_lack_caregiver()
        self._init_clients_and_caregivers()
        if not self.clients:
            logging.error("没有加载客户端，检查数据库或初始化进程。")
            raise ValueError("没有可用于调度的客户端。")
        self._init_elder_meal_activities()
        self.initial_temperature = params["initial_temperature"]
        self.cooling_rate = params["cooling_rate"]
        self.temperature = self.initial_temperature
        self.elder_actions: Dict[str, Set[int]] = self._load_elder_actions()
        self.all_nursing_actions = list(self.nursing_actions.keys())
        self.gpu_block_size = params.get("gpu_block_size", 256)
        self.caregiver_availability = {}
        self._init_caregiver_availability()
        self.generate_population()

        # 初始化CUDA上下文
        self.device = cp.cuda.Device(0)
        self.device.use()

    # 加载老人的活动需求
    def _load_elder_actions(self):
        elder_actions = {}
        elder_demands = Elderdemand.query.all()
        for demand in elder_demands:
            if demand.elder not in elder_actions:
                elder_actions[demand.elder] = set()
            if demand.actions:
                action_ids = [
                    int(action_id.strip())
                    for action_id in demand.actions.split(",")
                    if action_id.strip()
                ]
                elder_actions[demand.elder].update(action_ids)
            else:
                logging.warning(f"找不到护理动作 {demand.elder}")
        return elder_actions

    # 加载护理活动
    def load_nursing_actions(self):
        nursing_actions = {}
        actions = DicNursingAction.query.all()
        for action in actions:
            nursing_actions[action.id] = Activity(
                name=action.name,
                duration=30,  # 修改为30分钟
                required_skill=str(action.id),
            )

        # 确保关键活动存在
        # 饮食活动（ID为8）
        if 8 not in nursing_actions:
            nursing_actions[8] = Activity(name="饮食", duration=30, required_skill="8")
            logging.warning("数据库中没有饮食活动（ID=8），已创建默认饮食活动")

        # 睡眠活动（ID为10）
        if 10 not in nursing_actions:
            nursing_actions[10] = Activity(name="睡眠", duration=30, required_skill="10")
            logging.warning("数据库中没有睡眠活动（ID=10），已创建默认睡眠活动")

        # 添加优先活动列表中的所有活动ID
        priority_activities = [
            154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165,
            166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179
        ]
        for action_id in priority_activities:
            if action_id not in nursing_actions:
                nursing_actions[action_id] = Activity(
                    name=f"独立完成",
                    duration=30,
                    required_skill=str(action_id),
                )
                logging.warning(f"数据库中没有活动ID={action_id}，已创建默认活动")

        # 添加次要活动列表中的所有活动ID
        secondary_activities = [152, 153]
        for action_id in secondary_activities:
            if action_id not in nursing_actions:
                nursing_actions[action_id] = Activity(
                    name=f"独立完成",
                    duration=30,
                    required_skill=str(action_id),
                )
                logging.warning(f"数据库中没有活动ID={action_id}，已创建默认活动")

        logging.info(
            f"Loaded nursing actions: {len(nursing_actions)} activities"
        )
        return nursing_actions

    # 预留紧急时间槽
    def reserve_emergency_slots(self):
        return [
            random.randint(0, 47) for _ in range(6)
        ]  # 修改为48个时间段，增加紧急时间槽数量

    # 初始化客户和护理人员
    def _init_clients_and_caregivers(self):
        try:
            # 尝试从care_elder_demand表获取老人需求
            from app.new_models import CareElderDemand
            elder_demands = CareElderDemand.query.filter_by(
                arrange="1"
            ).all()  # 只选择arrange为'1'的老人

            if not elder_demands:
                # 如果从新表获取失败，则从原表获取
                logging.warning("从care_elder_demand表获取老人需求失败，使用elder_demand表获取")
                elder_demands = Elderdemand.query.filter_by(
                    arrange="1"
                ).all()  # 只选择arrange为'1'的老人
        except Exception as e:
            logging.error(f"从care_elder_demand表获取老人需求时出错: {str(e)}")
            # 从原表获取
            elder_demands = Elderdemand.query.filter_by(
                arrange="1"
            ).all()  # 只选择arrange为'1'的老人

        elder_actions = {}
        for demand in elder_demands:
            if demand.elder not in elder_actions:
                elder_actions[demand.elder] = set()
            if demand.actions:
                action_ids = [
                    int(action_id.strip())
                    for action_id in demand.actions.split(",")
                    if action_id.strip().isdigit()
                ]
                for action_id in action_ids:
                    if action_id in self.nursing_actions:
                        elder_actions[demand.elder].add(action_id)
                    else:
                        logging.warning(
                            f"护理动作ID {action_id} 未在老人需求表中 {demand.elder}"
                        )
            else:
                logging.warning(f"护理动作不在老人需求表中 {demand.elder}")

        # 使用client_num参数限制老人数量
        all_clients = [
            Client(elder=elder, actions=tuple(actions))
            for elder, actions in elder_actions.items()
        ]

        # 如果老人数量超过限制，随机选择指定数量的老人
        if len(all_clients) > self.client_num:
            logging.info(f"老人总数 {len(all_clients)} 超过限制 {self.client_num}，随机选择 {self.client_num} 个老人")
            self.clients = random.sample(all_clients, self.client_num)
        else:
            self.clients = all_clients

        logging.info(f"Loaded {len(self.clients)} clients from {len(all_clients)} total clients")

        # 获取所有护理员
        try:
            # 尝试从app_user和app_user_detail表获取护理员
            from app.db_adapter import DatabaseAdapter
            db_caregivers = DatabaseAdapter.get_caregivers()

            if not db_caregivers:
                # 如果从新表获取失败，则从原表获取
                logging.warning("从app_user和app_user_detail表获取护理员失败，使用attendant_skills表获取")
                all_caregivers = Attendantskills.query.all()
                temp_caregivers = []

                for cg in all_caregivers:
                    if cg.skills:
                        skills = frozenset(
                            int(skill)
                            for skill in cg.skills.split(",")
                            if skill.strip().isdigit()
                        )
                    else:
                        skills = frozenset()
                        logging.warning(
                            f"没有找到合适的护理员 {cg.attendant_name} (ID: {cg.id})"
                        )

                    caregiver = CaregiverData(
                        id=cg.id, attendant_name=cg.attendant_name, skills=skills
                    )
                    temp_caregivers.append(caregiver)
            else:
                # 从新表获取成功，将字典转换为CaregiverData对象
                temp_caregivers = []
                for cg in db_caregivers:
                    if cg.get('skills'):
                        skills = frozenset(
                            int(skill)
                            for skill in cg['skills'].split(",")
                            if skill.strip().isdigit()
                        )
                    else:
                        skills = frozenset()
                        logging.warning(
                            f"没有找到合适的护理员 {cg['name']} (ID: {cg['id']})"
                        )

                    caregiver = CaregiverData(
                        id=str(cg['id']), attendant_name=cg['name'], skills=skills
                    )
                    temp_caregivers.append(caregiver)
        except Exception as e:
            logging.error(f"从app_user和app_user_detail表获取护理员时出错: {str(e)}")
            # 从原表获取
            all_caregivers = Attendantskills.query.all()
            temp_caregivers = []

            for cg in all_caregivers:
                if cg.skills:
                    skills = frozenset(
                        int(skill)
                        for skill in cg.skills.split(",")
                        if skill.strip().isdigit()
                    )
                else:
                    skills = frozenset()
                    logging.warning(
                        f"没有找到合适的护理员 {cg.attendant_name} (ID: {cg.id})"
                    )

                caregiver = CaregiverData(
                    id=cg.id, attendant_name=cg.attendant_name, skills=skills
                )
                temp_caregivers.append(caregiver)

        # 使用caregiver_num参数限制护理员数量
        if len(temp_caregivers) > self.caregiver_num:
            logging.info(f"护理员总数 {len(temp_caregivers)} 超过限制 {self.caregiver_num}，随机选择 {self.caregiver_num} 个护理员")
            self.caregivers = random.sample(temp_caregivers, self.caregiver_num)
        else:
            self.caregivers = temp_caregivers

        logging.info(f"Loaded {len(self.caregivers)} caregivers from {len(temp_caregivers)} total caregivers")

    # 获取默认护理人员
    def get_default_caregiver(self):
        all_skills = frozenset(action_id for action_id in self.nursing_actions.keys())
        return CaregiverData(id="0", attendant_name="None", skills=all_skills)

    def get_lack_caregiver(self):
        all_skills = frozenset(action_id for action_id in self.nursing_actions.keys())
        return CaregiverData(id="-1", attendant_name="lack", skills=all_skills)

    # 初始化老人的用餐活动
    def _init_elder_meal_activities(self):
        default_meal_activity = min(self.meal_activities)
        for client in self.clients:
            elder_actions = set(client.actions)
            meal_actions = elder_actions.intersection(self.meal_activities)
            if meal_actions:
                self.elder_meal_activities[client.elder] = list(meal_actions)[0]
            else:
                self.elder_meal_activities[client.elder] = default_meal_activity
                logging.warning(
                    f"没给老人安排饮食动作 {client.elder}. 使用默认: {default_meal_activity}"
                )

    # 获取睡眠活动
    def get_sleep_activity(self):
        sleep_activity = next(
            (a for a in self.nursing_actions.values() if a.name == "睡眠"), None
        )
        if sleep_activity is None:
            logging.warning("未找到睡眠动作，自动创建一个睡眠动作")
            return Activity("睡眠", 30, required_skill="10")
        return sleep_activity

    # 获取用餐活动
    def get_meal_activity(self, elder, time):
        if time in self.meal_times:
            activity_id = self.elder_meal_activities.get(elder, 8)
            activity = self.nursing_actions.get(activity_id)
            if not activity:
                activity = Activity(name="饮食", duration=30, required_skill="8")
            logging.info(
                f"Meal activity for elder {elder} at time {time}: {activity.name} (ID: {activity_id})"
            )
            return activity
        return None

    # 选择活动
    def select_activity(self, client, time, scheduled_actions):
        if time in self.sleep_times:
            return self.get_sleep_activity()

        if time in self.meal_times:
            return self.get_meal_activity(client.elder, time)

        remaining_actions = set(client.actions) - scheduled_actions

        # 确保所有剩余活动都在nursing_actions字典中
        for action_id in remaining_actions:
            if action_id not in self.nursing_actions:
                # 如果不存在，创建一个默认活动
                logging.warning(f"护理动作ID {action_id} 不存在，创建默认活动")
                self.nursing_actions[action_id] = Activity(
                    name=f"独立完成",
                    duration=30,
                    required_skill=str(action_id),
                )

        possible_activities = [
            self.nursing_actions[action_id]
            for action_id in remaining_actions
            if action_id not in self.meal_activities
        ]

        if not possible_activities:
            logging.warning(
                f"No possible activities for client {client.elder} at time {time}"
            )
            # 如果没有可能的活动，返回一个默认活动
            if 154 in self.nursing_actions:  # 使用ID为154的活动作为默认
                logging.info(f"使用默认活动ID=154为客户 {client.elder} 在时间 {time}")
                return self.nursing_actions[154]
            return None

        selected_activity = random.choice(possible_activities)
        logging.info(
            f"Selected activity {selected_activity.name} for client {client.elder} at time {time}"
        )
        return selected_activity

    # 生成初始种群
    def generate_population(self):
        for _ in range(self.population_size):
            self.reset_caregiver_availability()
            plan_genes_list = []
            for client in self.clients:
                daily_schedule = []
                scheduled_actions = set()
                for current_time in range(48):  # 修改为48个时间段
                    time = current_time / 2  # 将索引转换为实际时间
                    if time in self.meal_times:
                        activity = self.get_meal_activity(client.elder, time)
                        caregiver = self.select_caregiver(client, time, activity)
                    elif time in self.sleep_times:
                        activity = self.get_sleep_activity()
                        caregiver = self.default_caregiver
                    else:
                        activity = self.select_activity(client, time, scheduled_actions)
                        caregiver = (
                            self.select_caregiver(client, time, activity)
                            if activity
                            else None
                        )

                    if activity:
                        if caregiver is None:
                            caregiver = self.default_caregiver
                        schedule = Schedule(start_time=time)
                        plan_genes = PlanGenes(
                            schedule=schedule,
                            caregiver=caregiver,
                            client=client,
                            activity=activity,
                        )
                        daily_schedule.append(plan_genes)
                        scheduled_actions.add(int(activity.required_skill))
                        logging.info(
                            f"Scheduled for client {client.elder} at time {time}: Activity {activity.name}, Caregiver {caregiver.attendant_name}"
                        )
                    else:
                        logging.warning(
                            f"No suitable activity found for client {client.elder} at time {time}"
                        )

                plan_genes_list.extend(daily_schedule)

            order = Order(order=plan_genes_list)
            self.orders.append(order)

        logging.info(f"Generated population with {len(self.orders)} orders")

    # 创建时间表条目
    def create_schedule_entry(self, current_time, activity, caregiver):
        from .care_utils import CareUtils

        start_hour = int(current_time)
        start_minute = int((current_time % 1) * 60)
        end_time = current_time + 0.5
        end_hour = int(end_time)
        end_minute = int((end_time % 1) * 60)

        activity_id = str(activity.required_skill) if activity and activity.required_skill else "0"
        activity_name = activity.name if activity else "No Activity"

        # 使用CareUtils获取活动名称
        if activity_id != "0" and activity_id != "10":  # 不处理睡眠活动
            try:
                # 尝试从digital_employee_skills表获取活动名称
                activity_name = CareUtils.get_activity_name_by_nursing_id(activity_id)
            except Exception as e:
                logging.warning(f"获取活动名称时出错: {str(e)}")

        return {
            "TimeSlot": f"{start_hour:02d}:{start_minute:02d}-{end_hour:02d}:{end_minute:02d}",
            "Activity": activity_name,
            "ActivityId": activity_id,
            "Caregiver": caregiver.attendant_name if caregiver else "No Caregiver",
            "CaregiverId": str(caregiver.id) if caregiver and caregiver.id else "0",
        }

    # 选择护理人员
    def select_caregiver(self, client, time, activity):
        required_skill = (
            int(activity.required_skill) if activity.required_skill.isdigit() else None
        )
        time_slot = int(time * 2)

        available_caregivers = [
            cg
            for cg in self.caregivers
            if self.is_caregiver_available(cg.id, time_slot)
            and (required_skill is None or required_skill in cg.skills)
        ]

        if not available_caregivers:
            if activity.name == "睡眠":
                return self.default_caregiver
            else:
                logging.warning(
                    f"护理员资源不足，无法为客户 {client.elder} 在时间 {time} 分配所需技能 {required_skill} 的护理员。使用 'lack' 护理员。"
                )
                return self.lack_caregiver

        selected_caregiver = random.choice(available_caregivers)
        self.set_caregiver_unavailable(selected_caregiver.id, time_slot)
        return selected_caregiver

    def calculate_skill_relevance_score(self, caregiver, required_skill_id):
        """计算护理员技能相关度评分"""
        # 获取所需技能的父级ID
        required_skill_pid = self.get_skill_pid(required_skill_id)
        # 获取所需技能的层级
        required_skill_level = self.get_skill_level(required_skill_id)

        base_score = 0
        if required_skill_id in caregiver.skills:
            # 完全匹配得满分
            base_score = 1.0
        else:
            # 检查护理员的所有技能
            for skill in caregiver.skills:
                skill_pid = self.get_skill_pid(skill)
                skill_level = self.get_skill_level(skill)

                # 同父级技能加分
                if skill_pid == required_skill_pid:
                    base_score += 0.5

                # 同级别技能加分
                if skill_level == required_skill_level:
                    base_score += 0.3

                # 高级别技能对低级别需求加分
                if skill_level < required_skill_level:
                    base_score += 0.2

        return min(base_score, 1.0)  # 确保评分不超过1.0

    def get_skill_pid(self, skill_id):
        """获取技能的父级ID"""
        for action in self.nursing_actions.values():
            if action.id == skill_id:
                return action.pid
        return None

    def get_skill_level(self, skill_id):
        """获取技能的层级"""
        for action in self.nursing_actions.values():
            if action.id == skill_id:
                return action.level
        return None

    def calculate_workload_balance(self, caregiver_id):
        """计算工作负载平衡度"""
        availability_array = self.caregiver_availability[caregiver_id]
        workload = 1 - (sum(availability_array) / len(availability_array))

        # 检查连续工作时间
        consecutive_work = 0
        max_consecutive = 0
        for available in availability_array:
            if not available:
                consecutive_work += 1
                max_consecutive = max(max_consecutive, consecutive_work)
            else:
                consecutive_work = 0

        # 根据最大连续工作时间调整工作负载评分
        workload_score = 1 - (workload * 0.7 + (max_consecutive / 8) * 0.3)
        return max(0, min(workload_score, 1.0))

    def reassign_caregiver(self, elder, time, activity):
        """优化后的护理员重分配策略"""
        try:
            client = next(c for c in self.clients if c.elder == elder)
            time_slot = int(time * 2)
            required_skill = (
                int(activity.required_skill)
                if activity.required_skill.isdigit()
                else None
            )

            if required_skill is None:
                return self.select_caregiver(client, time, activity)

            # 特殊处理睡眠活动
            if activity.name == "睡眠":
                return self.default_caregiver

            # 特殊处理用餐相关活动（pid=8的护理动作）
            if self.get_skill_pid(required_skill) == 8:
                # 优先选择有用餐照护经验的护理员
                meal_care_skills = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73}
                priority_caregivers = [
                    cg
                    for cg in self.caregivers
                    if self.is_caregiver_available(cg.id, time_slot)
                    and any(skill in cg.skills for skill in meal_care_skills)
                ]
                if priority_caregivers:
                    selected_caregiver = random.choice(priority_caregivers)
                    self.set_caregiver_unavailable(selected_caregiver.id, time_slot)
                    return selected_caregiver

            # 计算所有可用护理员的综合评分
            available_caregivers = []
            for caregiver in self.caregivers:
                if not self.is_caregiver_available(caregiver.id, time_slot):
                    continue

                # 技能相关度评分（占比50%）
                skill_score = self.calculate_skill_relevance_score(
                    caregiver, required_skill
                )

                # 工作负载平衡评分（占比30%）
                workload_score = self.calculate_workload_balance(caregiver.id)

                # 护理级别匹配评分（占比20%）
                level_score = (
                    1.0
                    if self.get_skill_level(required_skill)
                    in {self.get_skill_level(skill) for skill in caregiver.skills}
                    else 0.0
                )

                # 计算综合评分
                total_score = (
                    skill_score * 0.5 + workload_score * 0.3 + level_score * 0.2
                )

                available_caregivers.append((caregiver, total_score))

            if not available_caregivers:
                logging.warning(
                    f"重分配失败: 无可用护理员 - 老人: {elder}, "
                    f"时间: {time}, 活动: {activity.name}"
                )
                return self.lack_caregiver

            # 选择评分最高的护理员
            selected_caregiver = max(available_caregivers, key=lambda x: x[1])[0]
            self.set_caregiver_unavailable(selected_caregiver.id, time_slot)

            logging.info(
                f"重分配成功: 老人: {elder}, "
                f"护理员: {selected_caregiver.attendant_name}, "
                f"时间: {time}, 活动: {activity.name}, "
                f"技能要求: {required_skill}"
            )

            return selected_caregiver

        except Exception as e:
            logging.error(f"重分配过程发生错误: {str(e)}")
            return self.lack_caregiver

    def is_caregiver_available(self, caregiver_id, time_slot):
        return self.caregiver_availability[caregiver_id][time_slot]

    def set_caregiver_unavailable(self, caregiver_id, time_slot):
        self.caregiver_availability[caregiver_id][time_slot] = False

    # 计算适应度
    @diagnose_gpu_utilization
    def cal_fitness(self):
        all_order_data = [
            (int(gene.activity.required_skill), hash(gene.caregiver), hash(gene.client))
            for order in self.orders
            for gene in order.order
        ]

        print(f"all_order_data length: {len(all_order_data)}")

        if not all_order_data:
            print("Warning: all_order_data is empty")
            return 0

        all_order_data = cp.array(all_order_data, dtype=cp.int64)

        print(f"CuPy array shape: {all_order_data.shape}")

        try:
            # 奖励非默认活动
            non_default_activity = (all_order_data[:, 0] != 10).astype(cp.int32) * 5
            print(f"Sum of non_default_activity: {cp.sum(non_default_activity)}")

            # 放宽技能匹配逻辑
            skill_match = (
                all_order_data[:, 0] % 10 == all_order_data[:, 1] % 10
            ).astype(cp.int32) * 10
            print(f"Sum of skill_match: {cp.sum(skill_match)}")

            # 奖励客户多样性（如果连续的活动属于不同的客户）
            client_diversity = (all_order_data[1:, 2] != all_order_data[:-1, 2]).astype(
                cp.int32
            ) * 8
            client_diversity = cp.concatenate(
                [cp.array([0]), client_diversity]
            )  # 为第一个活动添加0
            print(f"Sum of client_diversity: {cp.sum(client_diversity)}")

            # 奖励活动多样性
            activity_diversity = (
                all_order_data[1:, 0] != all_order_data[:-1, 0]
            ).astype(cp.int32) * 5
            activity_diversity = cp.concatenate(
                [cp.array([0]), activity_diversity]
            )  # 为第一个活动添加0
            print(f"Sum of activity_diversity: {cp.sum(activity_diversity)}")

            # 奖励稀有活动（假设活动ID越大越稀有）
            rare_activity = (all_order_data[:, 0] // 10).astype(
                cp.float32
            )  # 将活动ID除以10，以减小数值
            rare_activity = rare_activity / cp.max(rare_activity) * 20  # 归一化并乘以20
            print(f"Sum of rare_activity: {cp.sum(rare_activity)}")

            # 总适应度是所有因素的和
            combined_fitness = (
                non_default_activity
                + skill_match
                + client_diversity
                + activity_diversity
                + rare_activity
            )
            print(f"Sum of combined_fitness: {cp.sum(combined_fitness)}")

            # 计算每个订单的适应度
            genes_per_order = len(self.orders[0].order)  # 假设每个订单的基因数量相同
            fitness_values = cp.sum(
                combined_fitness.reshape(-1, genes_per_order), axis=1
            )
            print(f"fitness_values shape: {fitness_values.shape}")
            print(f"Max fitness value: {cp.max(fitness_values)}")
            print(f"Min fitness value: {cp.min(fitness_values)}")
            print(f"Average fitness value: {cp.mean(fitness_values)}")
            print(f"Fitness value standard deviation: {cp.std(fitness_values)}")
        except Exception as e:
            print(f"Error during fitness calculation: {str(e)}")
            return 0

        fitness_values_cpu = fitness_values.get()

        for order, fitness in zip(self.orders, fitness_values_cpu):
            order.fitness = int(fitness)

        avg_fitness = np.mean(fitness_values_cpu)
        print(f"平均适应度: {avg_fitness}")
        return avg_fitness

    # 选择父代
    def select_parents(self):
        # 将选择移到GPU
        fitness_values = cp.array(
            [order.fitness for order in self.orders], dtype=cp.float32
        )
        sorted_indices = cp.argsort(fitness_values)[::-1]
        selected_indices = sorted_indices[: self.tournament_size].get()
        self.orders = [self.orders[i] for i in selected_indices]

    # 模拟退火交叉
    @diagnose_gpu_utilization
    def simulated_annealing_crossover(self, parent1, parent2):
        crossover_point = random.randint(0, len(parent1.order))
        child = Order(
            order=parent1.order[:crossover_point] + parent2.order[crossover_point:]
        )

        # 将退火过程移到GPU
        child_data = cp.array(
            [
                (
                    int(gene.schedule.start_time * 2),
                    int(gene.activity.required_skill),
                    hash(gene.client),
                    hash((gene.caregiver.id, gene.caregiver.attendant_name)),
                )
                for gene in child.order
            ],
            dtype=cp.int64,
        )
        temperature = cp.float32(self.temperature)

        # 使用cupy进行随机数生成和向量操作
        random_values = cp.random.random(len(child_data))
        mutation_mask = cp.exp(-1 / temperature) > random_values

        mutated_times = cp.random.randint(0, 48, size=len(child_data))
        mutated_activities = cp.random.randint(
            0, len(self.nursing_actions), size=len(child_data)
        )

        child_data[mutation_mask, 0] = mutated_times[mutation_mask]
        child_data[mutation_mask, 1] = mutated_activities[mutation_mask]

        # 将结果传回CPU
        mutated_indices = cp.where(mutation_mask)[0].get()

        # 基于GPU计算更新子代order
        for i in mutated_indices:
            gene = child.order[i]
            current_time = child_data[i, 0] / 2
            if current_time not in self.sleep_times:
                new_activity_id = int(child_data[i, 1])
                new_activity = self.nursing_actions.get(
                    new_activity_id,
                    self.select_activity(gene.client, current_time, set()),
                )
                if new_activity:
                    new_caregiver = self.select_caregiver(
                        gene.client, current_time, new_activity
                    )
                    if new_caregiver:
                        child.order[i] = PlanGenes(
                            Schedule(current_time),
                            new_caregiver,
                            gene.client,
                            new_activity,
                        )

        return child

    # 交叉和变异
    @diagnose_gpu_utilization
    def crossover_and_mutation(self):
        orders = self.orders.copy()
        while len(orders) < self.population_size:
            if random.random() < self.crossover_rate:
                parent1, parent2 = random.sample(orders, 2)
                child1 = self.simulated_annealing_crossover(parent1, parent2)
                child2 = self.simulated_annealing_crossover(parent2, parent1)
                orders.extend([child1, child2])

            mutation_count = int(self.population_size * self.mutation_rate)
            mutation_indices = cp.random.choice(
                len(orders), size=mutation_count, replace=False
            )

            for i in mutation_indices.get():
                self.reset_caregiver_availability()  # 重置护理员可用性
                order = orders[i]

                for gene in order.order:
                    time_slot = int(gene.schedule.start_time * 2)
                    self.set_caregiver_unavailable(gene.caregiver.id, time_slot)

                gene_index = random.randint(0, len(order.order) - 1)
                gene = order.order[gene_index]
                current_time = gene.schedule.start_time

                if current_time in self.sleep_times:
                    new_activity = self.get_sleep_activity()
                    new_caregiver = self.default_caregiver
                elif current_time in self.meal_times:
                    meal_activity = self.get_meal_activity(
                        gene.client.elder, current_time
                    )
                    if meal_activity:
                        new_activity = meal_activity
                        new_caregiver = self.select_caregiver(
                            gene.client, current_time, new_activity
                        )
                    else:
                        new_activity = self.select_activity(
                            gene.client, current_time, set()
                        )
                        new_caregiver = (
                            self.select_caregiver(
                                gene.client, current_time, new_activity
                            )
                            if new_activity
                            else None
                        )
                else:
                    scheduled_actions = set(
                        int(g.activity.required_skill)
                        for g in order.order
                        if g.client == gene.client
                    )
                    required_actions = set(self.elder_actions[gene.client.elder])
                    unscheduled_actions = (
                        required_actions
                        - scheduled_actions
                        - self.meal_activities
                        - {10}
                    )

                    if unscheduled_actions:
                        new_activity_id = random.choice(list(unscheduled_actions))
                        new_activity = self.nursing_actions[new_activity_id]
                    else:
                        new_activity = self.select_activity(
                            gene.client, current_time, scheduled_actions
                        )

                    new_caregiver = (
                        self.select_caregiver(gene.client, current_time, new_activity)
                        if new_activity
                        else None
                    )

                if new_activity:
                    if new_caregiver is None:
                        new_caregiver = self.default_caregiver
                    new_gene = PlanGenes(
                        gene.schedule, new_caregiver, gene.client, new_activity
                    )
                    order.order[gene_index] = new_gene

                    # 更新护理员可用性
                    time_slot = int(new_gene.schedule.start_time * 2)
                    self.set_caregiver_unavailable(new_caregiver.id, time_slot)
                else:
                    order.order.pop(gene_index)

                # 重新评估订单的适应度
                order.fitness = self.calculate_order_fitness(order)

        # 根据适应度对订单进行排序，并保留前 population_size 个订单
        orders.sort(key=lambda x: x.fitness, reverse=True)
        self.orders = orders[: self.population_size]

        # 更新温度
        self.temperature *= self.cooling_rate

    def validate_schedule(self, client_schedules):
        for elder, schedule in client_schedules.items():
            caregiver_schedules = {}
            for time_slot, entry in enumerate(schedule):
                if entry:
                    caregiver = entry["Caregiver"]
                    if caregiver not in caregiver_schedules:
                        caregiver_schedules[caregiver] = set()
                    if time_slot in caregiver_schedules[caregiver]:
                        logging.warning(
                            f"时间冲突: 护理员 {caregiver} 在时间段 {time_slot / 2} 被重复分配给老人 {elder}"
                        )
                        # 这里可以添加解决冲突的逻辑，例如重新分配护理员
                        new_caregiver = self.reassign_caregiver(
                            elder, time_slot / 2, entry["Activity"]
                        )
                        if new_caregiver:
                            entry["Caregiver"] = new_caregiver.attendant_name
                            entry["CaregiverId"] = new_caregiver.id
                        else:
                            entry["Caregiver"] = "未分配"
                            entry["CaregiverId"] = "0"
                    caregiver_schedules[caregiver].add(time_slot)

    # 提供一个安全的事务上下文
    @staticmethod
    @contextmanager
    def safe_transaction(session):
        try:
            yield
            session.commit()
        except Exception:
            session.rollback()
            raise

    # 保存到数据库
    def save_to_database(self, client_schedules):
        current_datetime = datetime.now()

        for elder, schedule in client_schedules.items():
            try:
                with self.safe_transaction(db.session):
                    logging.info(f"Processing schedule for elder {elder}")

                    if schedule is None:
                        logging.warning(f"Schedule for elder {elder} is None")
                        continue

                    if not isinstance(schedule, list):
                        logging.warning(
                            f"Schedule for elder {elder} is not a list. Type: {type(schedule)}"
                        )
                        continue

                    valid_schedule = []
                    for i, slot in enumerate(schedule):
                        if slot is None:
                            logging.warning(f"Slot {i} for elder {elder} is None")
                            continue
                        if not isinstance(slot, dict):
                            logging.warning(
                                f"Slot {i} for elder {elder} is not a dict. Type: {type(slot)}"
                            )
                            continue
                        if "TimeSlot" not in slot:
                            logging.warning(
                                f"Slot {i} for elder {elder} does not have 'TimeSlot' key. Keys: {slot.keys()}"
                            )
                            continue
                        valid_schedule.append(slot)

                    if not valid_schedule:
                        logging.warning(f"No valid slots for elder {elder}")
                        continue

                    sorted_schedule = sorted(
                        valid_schedule,
                        key=lambda x: datetime.strptime(
                            x["TimeSlot"].split("-")[0], "%H:%M"
                        ),
                    )

                    existing_result = ScheduleResult.query.filter_by(
                        elder=elder, schedule_date=current_datetime.date()
                    ).first()

                    if existing_result:
                        existing_result.schedule_data = sorted_schedule
                        existing_result.schedule_date = current_datetime
                        TimeSlot.query.filter_by(
                            schedule_result_id=existing_result.id
                        ).delete()
                    else:
                        existing_result = ScheduleResult(
                            id=str(uuid4()),
                            elder=elder,
                            schedule_date=current_datetime,
                            schedule_data=sorted_schedule,
                        )
                        db.session.add(existing_result)

                    db.session.flush()

                    time_slots_to_add = []
                    for index, slot in enumerate(sorted_schedule):
                        if (
                            "TimeSlot" in slot
                            and "Activity" in slot
                            and "ActivityId" in slot
                            and "Caregiver" in slot
                            and "CaregiverId" in slot
                        ):
                            new_time_slot = TimeSlot(
                                id=str(uuid4()),
                                schedule_result_id=existing_result.id,
                                elder=elder,
                                time_slot=slot["TimeSlot"],
                                activity=slot["Activity"],
                                activity_id=slot["ActivityId"],
                                caregiver=(
                                    "lack"
                                    if slot["CaregiverId"] == "-1"
                                    else slot["Caregiver"]
                                ),
                                caregiver_id=slot["CaregiverId"],
                                time_order=index,
                                schedule_date=current_datetime,
                            )
                            time_slots_to_add.append(new_time_slot)
                        else:
                            logging.warning(
                                f"Incomplete slot data for elder {elder} at index {index}: {slot}"
                            )

                    db.session.bulk_save_objects(time_slots_to_add)

                logging.info(
                    f"Created/Updated schedule for elder {elder} on {current_datetime}"
                )

            except Exception as e:
                logging.error(
                    f"Error saving schedules to database for elder {elder}: {str(e)}",
                    exc_info=True,
                )

        logging.info(
            f"Successfully saved/updated schedules for {len(client_schedules)} elders on {current_datetime}"
        )

    # 运行算法
    @diagnose_gpu_utilization
    def run(self):
        for generation in range(self.phenotype_limit):
            start_time = time.time()
            self.batch_process()  # 使用批处理方法
            self.select_parents()
            end_time = time.time()

            logging.info(
                f"Generation {generation + 1} took {end_time - start_time:.2f} seconds"
            )

            logging.info(
                f"GPU memory usage: {cp.get_default_memory_pool().used_bytes() / 1024 ** 2:.2f} MB"
            )

            logging.info(
                f"Best Fitness: {max(order.fitness for order in self.orders)}, Temperature: {self.temperature:.2f}"
            )

            cp.cuda.Stream.null.synchronize()

        self.cal_fitness()
        self.orders.sort(key=lambda x: x.fitness, reverse=True)
        logging.info(f"最优解: {self.orders[0].fitness}")

        client_schedules = {}
        for client in self.clients:
            elder_demand = Elderdemand.query.filter_by(
                elder=client.elder, arrange="1"
            ).first()
            if not elder_demand:
                logging.info(
                    f"Skipping schedule generation for elder {client.elder} (arrange != '1')"
                )
                continue

            client_schedules[client.elder] = [None] * 48  # 修改为48个30分钟时间段
            required_actions = (
                set(client.actions) - self.meal_activities - {10}
            )  # 排除饮食和睡眠活动
            scheduled_actions = set()

            # 安排睡眠活动
            for sleep_time in self.sleep_times:
                activity = self.get_sleep_activity()
                caregiver = self.default_caregiver
                time_index = int(sleep_time * 2)
                client_schedules[client.elder][time_index] = self.create_schedule_entry(
                    sleep_time, activity, caregiver
                )

            # 安排饮食活动
            for meal_time in self.meal_times:
                activity = self.get_meal_activity(client.elder, meal_time)
                caregiver = self.select_caregiver(client, meal_time, activity)
                time_index = int(meal_time * 2)
                client_schedules[client.elder][time_index] = self.create_schedule_entry(
                    meal_time, activity, caregiver
                )

            # 安排其他必需活动
            available_times = [
                t / 2 for t in range(48) if client_schedules[client.elder][t] is None
            ]
            random.shuffle(available_times)  # 随机打乱可用时间，以便更均匀地分配活动

            for action_id in required_actions:
                if action_id not in scheduled_actions and available_times:
                    activity = self.nursing_actions[action_id]
                    current_time = available_times.pop()
                    caregiver = self.select_caregiver(client, current_time, activity)
                    time_index = int(current_time * 2)
                    client_schedules[client.elder][time_index] = (
                        self.create_schedule_entry(current_time, activity, caregiver)
                    )
                    scheduled_actions.add(action_id)
                    logging.info(
                        f"为老人 {client.elder} 安排活动 {activity.name} 在时间 {current_time}"
                    )

            # 检查是否所有必需活动都已安排
            unscheduled_actions = required_actions - scheduled_actions
            if unscheduled_actions:
                logging.warning(
                    f"无法为老人 {client.elder} 安排以下活动: {unscheduled_actions}"
                )

            # 填充剩余的空闲时间
            priority_activities = [
                154,
                155,
                156,
                157,
                158,
                159,
                160,
                161,
                162,
                163,
                164,
                165,
                166,
                167,
                168,
                169,
                170,
                171,
                172,
                173,
                174,
                175,
                176,
                177,
                178,
                179,
            ]
            secondary_activities = [152, 153]

            available_times = [
                t / 2 for t in range(48) if client_schedules[client.elder][t] is None
            ]

            # 先尝试安排所有优先活动
            for action_id in priority_activities:
                if available_times:
                    # 添加错误处理，检查action_id是否存在于nursing_actions字典中
                    if action_id not in self.nursing_actions:
                        # 如果不存在，创建一个默认活动
                        logging.warning(f"护理动作ID {action_id} 不存在，创建默认活动")
                        self.nursing_actions[action_id] = Activity(
                            name=f"独立完成",
                            duration=30,
                            required_skill=str(action_id),
                        )

                    activity = self.nursing_actions[action_id]
                    current_time = available_times.pop(0)
                    caregiver = self.select_caregiver(client, current_time, activity)
                    time_index = int(current_time * 2)
                    client_schedules[client.elder][time_index] = (
                        self.create_schedule_entry(current_time, activity, caregiver)
                    )
                    logging.info(
                        f"为老人 {client.elder} 安排优先活动 {activity.name} 在时间 {current_time}"
                    )
                else:
                    break

            # 更新可用时间
            available_times = [
                t / 2 for t in range(48) if client_schedules[client.elder][t] is None
            ]

            # 如果还有剩余时间，再安排次要活动
            if available_times:
                for action_id in secondary_activities:
                    if available_times:
                        # 添加错误处理，检查action_id是否存在于nursing_actions字典中
                        if action_id not in self.nursing_actions:
                            # 如果不存在，创建一个默认活动
                            logging.warning(f"护理动作ID {action_id} 不存在，创建默认活动")
                            self.nursing_actions[action_id] = Activity(
                                name=f"独立完成",
                                duration=30,
                                required_skill=str(action_id),
                            )

                        activity = self.nursing_actions[action_id]
                        current_time = available_times.pop(0)
                        caregiver = self.select_caregiver(
                            client, current_time, activity
                        )
                        time_index = int(current_time * 2)
                        client_schedules[client.elder][time_index] = (
                            self.create_schedule_entry(
                                current_time, activity, caregiver
                            )
                        )
                        logging.info(
                            f"为老人 {client.elder} 安排次要活动 {activity.name} 在时间 {current_time}"
                        )
                    else:
                        break

            # 如果还有剩余的空闲时间，用随机活动填充
            while available_times:
                current_time = available_times.pop(0)
                # 确保随机选择的活动ID存在于nursing_actions字典中
                valid_activity_ids = [id for id in self.all_nursing_actions if id in self.nursing_actions]
                if not valid_activity_ids:
                    # 如果没有有效的活动ID，创建一个默认活动
                    default_activity_id = 8  # 使用ID为8的活动作为默认
                    if default_activity_id not in self.nursing_actions:
                        logging.warning(f"创建默认活动ID {default_activity_id}")
                        self.nursing_actions[default_activity_id] = Activity(
                            name="日常活动",
                            duration=30,
                            required_skill=str(default_activity_id),
                        )
                    random_activity_id = default_activity_id
                else:
                    random_activity_id = random.choice(valid_activity_ids)

                activity = self.nursing_actions[random_activity_id]
                caregiver = self.select_caregiver(client, current_time, activity)
                time_index = int(current_time * 2)
                client_schedules[client.elder][time_index] = self.create_schedule_entry(
                    current_time, activity, caregiver
                )
                logging.info(
                    f"为老人 {client.elder} 安排随机活动 {activity.name} 在时间 {current_time}"
                )

        # 验证并修正调度
        self.validate_schedule(client_schedules)
        self.save_to_database(client_schedules)

        # 添加这一行来保存护理人员的调度
        self.save_caregiver_schedules(date.today())

        best_order = max(self.orders, key=lambda x: x.fitness)
        logging.info(f"最优解适应度: {best_order.fitness}")
        logging.info(f"最终退火温度: {self.temperature:.4f}")
        print(f"最优解适应度: {best_order.fitness}")
        print(f"最终退火温度: {self.temperature:.4f}")

        # 更新Redis中的时间和标志
        set_update_time()
        set_update_flag()

        return client_schedules

    def save_caregiver_schedules(self, schedule_date):
        """保存护理人员的调度到数据库"""
        for caregiver_id, availability in self.caregiver_availability.items():
            for time_slot, is_available in enumerate(availability):
                # 将时间槽转换为实际时间
                slot_time = datetime.combine(
                    schedule_date, datetime.min.time()
                ) + timedelta(minutes=30 * time_slot)

                # 检查是否已存在该护理人员在该日期和时间段的记录
                existing_schedule = CaregiverSchedule.query.filter_by(
                    caregiver_id=caregiver_id,
                    schedule_date=slot_time.date(),
                    time_slot=time_slot,
                ).first()

                if existing_schedule:
                    # 如果记录存在，更新可用性和时间
                    existing_schedule.is_available = is_available
                    existing_schedule.schedule_date = slot_time
                else:
                    # 如果记录不存在，创建新记录
                    new_schedule = CaregiverSchedule(
                        caregiver_id=caregiver_id,
                        schedule_date=slot_time,
                        time_slot=time_slot,
                        is_available=is_available,
                    )
                    db.session.add(new_schedule)

        try:
            db.session.commit()
            logging.info(f"成功保存护理人员调度到数据库，日期：{schedule_date}")
        except Exception as e:
            db.session.rollback()
            logging.error(f"保存护理人员调度时发生错误：{str(e)}")

    def _init_caregiver_availability(self):
        for caregiver in self.caregivers:
            self.caregiver_availability[caregiver.id] = [True] * 48  # 48个30分钟时间段

    # 以下函数已在前面定义，这里的重复定义已被移除
    # def is_caregiver_available(self, caregiver_id: str, time_slot: int) -> bool:
    #     return self.caregiver_availability[caregiver_id][time_slot]
    #
    # def set_caregiver_unavailable(self, caregiver_id: str, time_slot: int):
    #     self.caregiver_availability[caregiver_id][time_slot] = False

    def reset_caregiver_availability(self):
        for caregiver_id in self.caregiver_availability:
            self.caregiver_availability[caregiver_id] = [True] * 48

    # 批处理方法
    @diagnose_gpu_utilization
    def batch_process(self, batch_size=1000):
        for i in range(0, len(self.orders), batch_size):
            batch = self.orders[i : i + batch_size]

            # 将批次数据移到 GPU
            batch_data = []
            for order in batch:
                for gene in order.order:
                    batch_data.append(
                        [
                            int(gene.activity.required_skill),
                            hash(gene.caregiver),
                            hash(gene.client),
                        ]
                    )

            if not batch_data:
                logging.warning(f"Empty batch data for batch starting at index {i}")
                continue

            batch_data = cp.array(batch_data, dtype=cp.int64)
            logging.info(f"Batch data shape: {batch_data.shape}")

            try:
                # 在 GPU 上计算适应度
                condition1 = batch_data[:, 0] != 10
                logging.info(f"Condition1 shape: {condition1.shape}")
                condition2 = batch_data[:, 0] == batch_data[:, 1]
                logging.info(f"Condition2 shape: {condition2.shape}")
                combined_condition = condition1 & condition2
                logging.info(f"Combined condition shape: {combined_condition.shape}")

                genes_per_order = len(
                    self.orders[0].order
                )  # 假设每个订单的基因数量相同
                fitness_values = cp.sum(
                    combined_condition.reshape(-1, genes_per_order), axis=1
                )
                logging.info(f"Fitness values shape: {fitness_values.shape}")

                # 将结果移回 CPU 并更新订单
                fitness_values_cpu = fitness_values.get()
                for j, order in enumerate(batch):
                    order.fitness = int(fitness_values_cpu[j])

                logging.info(
                    f"Processed batch of size {len(batch)} (orders {i} to {i + len(batch) - 1})"
                )
                logging.info(f"Max fitness in batch: {cp.max(fitness_values)}")
                logging.info(f"Min fitness in batch: {cp.min(fitness_values)}")
                logging.info(f"Average fitness in batch: {cp.mean(fitness_values)}")

            except Exception as e:
                logging.error(f"Error processing batch: {str(e)}")
                logging.error(f"Batch data: {batch_data}")
                continue

        # 更新温度
        self.temperature *= self.cooling_rate


if __name__ == "__main__":
    plan = Plan(params)
    try:
        client_schedules = plan.run()
        output_directory = "/mnt/d/ruanjian/Anaconda3/tf2/suanfa/app/schedules"
        os.makedirs(output_directory, exist_ok=True)

        for elder, schedule in client_schedules.items():
            df = pd.DataFrame(schedule, columns=["TimeSlot", "Activity", "Caregiver"])
            output_file_name = f"{elder}_schedule.xlsx"
            output_file_path = os.path.join(output_directory, output_file_name)
            df.to_excel(output_file_path, index=False)
            logging.info(f"Schedule for elder {elder} saved to {output_file_path}")

    except Exception as e:
        logging.error(f"An error occurred: {str(e)}")
    finally:
        # 清理 GPU 内存
        mempool = cp.get_default_memory_pool()
        pinned_mempool = cp.get_default_pinned_memory_pool()
        mempool.free_all_blocks()
        pinned_mempool.free_all_blocks()
        logging.info("GPU memory cleaned up")
